﻿#include <memory>
#include "basemodbus.h"

BaseModbus::BaseModbus(QObject *parent):BaseCommunication(parent)
{

}

BaseModbus::~BaseModbus()
{
    modbus_close(m_ctx);
    modbus_free(m_ctx);
}

QList<uint16_t> BaseModbus::readRegisters(int addr, int count)
{
    QMutexLocker locker(&_mutex);
    uint16_t *dest=new uint16_t[count];
    int retCount=modbus_read_registers(m_ctx,addr,count,dest);

    if(retCount!=count)
    {
        throw QString("%1 readRegisters(%2,%3) err").arg(_name).arg(addr).arg(count);
    };

    QList<uint16_t> target;
    pointToList(dest,retCount,target);
    return target;
}

uint16_t BaseModbus::readRegister(int addr)
{
    QList<uint16_t> ret=readRegisters(addr,1);
    return ret.at(0);
}

QList<uint16_t> BaseModbus::readInputRegisters(int addr, int count)
{
    QMutexLocker locker(&_mutex);
    uint16_t *dest=new uint16_t[count];
    int retCount=modbus_read_input_registers(m_ctx,addr,count,dest);
    if(retCount!=count)
    {
        throw QString("%1 readInputRegisters(%2,%3) err").arg(_name).arg(addr).arg(count);
    }

    QList<uint16_t> target;
    pointToList(dest,retCount,target);
    return target;
}

uint16_t BaseModbus::readInputRegister(int addr)
{
    QList<uint16_t> ret=readInputRegisters(addr,1);
    return ret.at(0);
}

bool BaseModbus::writeRegisters(int addr, int count, QList<uint16_t> inputList)
{
    QMutexLocker locker(&_mutex);
    std::vector<uint16_t> data = inputList.toVector().toStdVector();
    if(data.size()!=count)
    {
        return false;
    }
    int retCount=modbus_write_registers(m_ctx,addr,count,data.data());
    return retCount=count;
}

bool BaseModbus::writeRegister(int addr, uint16_t inputList)
{
    return writeRegisters(addr,1,QList<uint16_t>()<<inputList);
}

QList<bool> BaseModbus::readBits(int addr, int count)
{
    QMutexLocker locker(&_mutex);
//    std::unique_ptr<uint8_t[]> dest(new uint8_t[count]);
    uint8_t* dest=new uint8_t[count];
    int retCount=modbus_read_bits(m_ctx,addr,count,dest);
    QList<bool> retList;
    if(retCount!=count)
    {
        throw QString("%1 readBits(%2,%3) err").arg(_name).arg(addr).arg(count);
    }
    for(int i=0;i<count;i++)
    {
        retList.append(dest[i]);
    }
    delete[] dest;
    return retList;
}

bool BaseModbus::readBit(int addr)
{
    QList<bool> ret=readBits(addr,1);
    return ret.at(0);
}

QList<bool> BaseModbus::readInputBits(int addr, int count)
{
    QMutexLocker locker(&_mutex);
    std::unique_ptr<uint8_t[]> dest(new uint8_t[count]);
    int retCount=modbus_read_input_bits(m_ctx,addr,count,dest.get());
    QList<bool> retList;
    if(retCount!=count)
    {
        throw QString("%1 readInputBits(%2,%3) err").arg(_name).arg(addr).arg(count);
    }

    for(int i=0;i<count;i++)
    {
        retList.append(dest[i]);
    }
    return retList;
}

bool BaseModbus::readInputBit(int addr)
{
    QList<bool> ret=readInputBits(addr,1);
    return ret.at(0);
}

bool BaseModbus::writeBits(int addr, int count, QList<bool> coilStates)
{
    QMutexLocker locker(&_mutex);
    std::vector<uint8_t> bits(coilStates.size());
    for (int i = 0; i < count; ++i) {
        bits[i] = coilStates[i] ? 1 : 0;
    }
    int ret = modbus_write_bits(m_ctx, addr, count, bits.data());

    if (ret == -1)
    {
        throw QString("%1 writeBits(%2,%3) err").arg(_name).arg(addr).arg(count);
    }
    return true;
}

bool BaseModbus::writeBit(int addr, bool coilState)
{
    //return writeRegisters(addr,1,QList<uint16_t>()<<inputList);
    return writeBits(addr,1,QList<bool>()<<coilState);
}

bool BaseModbus::connectToHost()
{
    //设置1000ms的超时
    modbus_set_response_timeout(m_ctx,0,1000*1000);
    //设置为1时断开重连有效，设置为0时程序会卡死
    //后来发现libmodbus版本问题，升级到新版本就行了
    int ret = modbus_set_error_recovery(m_ctx,static_cast<modbus_error_recovery_mode>(MODBUS_ERROR_RECOVERY_LINK|MODBUS_ERROR_RECOVERY_PROTOCOL));

    //设置slave地址
    modbus_set_slave(m_ctx, 1);
    ret = modbus_connect(m_ctx);
    bool isConnected=(ret!=-1);
    return isConnected;
}

bool BaseModbus::isConnected()
{
    return true;
}

bool BaseModbus::disConnect()
{
    modbus_close(m_ctx);
    m_ctx=nullptr;
    qDebug()<<__FUNCTION__<<__LINE__<<m_ctx;
    return true;
}
